"""
@ Author:AS.CK
@ File:svm_minist.py
@ Date: 2021-02-20
@ Function:Use SVM to achieve minist classification
@ Python 3.6.8
@ Data Source:http://yann.lecun.com/exdb/mnist/

"""
# ________________________________________________________________________________
import struct
import sklearn
from   sklearn import svm
import numpy  as np
import matplotlib.pyplot as plt
import matplotlib
from   sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import matplotlib.image as img  # 用于显示图片

# 读取数据集
train_image_path = '../DATASET/MINIST/train-images.idx3-ubyte'
train_label_path = '../DATASET/MINIST/train-labels.idx1-ubyte'
test_image_path  = '../DATASET/MINIST/t10k-images.idx3-ubyte'
test_label_path  = '../DATASET/MINIST/t10k-labels.idx1-ubyte'

with open(train_image_path, 'rb') as f1:
     train_image_file = f1.read()
     numfile = struct.unpack('>I',train_image_file[4:8])
     numfiles = numfile[0]
     train_image_file = train_image_file[16:]
with open(train_label_path, 'rb') as f1:
     train_label_file = f1.read()
     train_label_file = train_label_file[8:]

dataSet =np.zeros([numfiles,784],int) #用于存放所有的数字文件
# hwLabels =np.zeros([numfiles,10]) #用于存放对应的标签one-hot,在这个SVM里不需要做
hwLabels =np.zeros(numfiles)

for i in range(numfiles):
    label = train_label_file[i]
    hwLabels[i] = label
    dataSet[i] = [int(item) for item in train_image_file[i*784:i*784+784]]
    
    num = numfiles / 10
    if (i+1) % num == 0:
        percent = i / numfiles * 100
        print("AS.CK :>","%.2f"%percent,"%\r")
        # 查看解码的图像是否正确
        # image =  np.array(dataSet[i], dtype=np.uint8).reshape(28,28)
        # plt.imshow(image)
        # plt.show()


print('AS.CK :> 开始训练...')
classifier=svm.SVC(C=2,kernel='rbf',gamma=10,decision_function_shape='ovo') # ovr:一对多策略
# classifier = svm.SVC(gamma=0.001, C=100.,decision_function_shape='ovr')
classifier.fit(dataSet[:30000],hwLabels[:30000].ravel()) #ravel函数在降维时默认是行序优先,将数组变为一维数组，这里没必要，但是保留了形式
 
# 模型测试，返回正确率
test_score = classifier.score(dataSet, hwLabels)        #score(测试集样本，测试集标记)
print("AS.CK :> 测试得分：%.2f"%test_score)

# 使用分类器
target_source =  img.imread('../DATASET/MINIST/测试.png')
target_source = np.dot(target_source[...,:3], [0.299, 0.587, 0.114]) * 255
target =np.array(target_source, dtype=np.uint8).reshape(1,28*28)
result = classifier.predict(target)

# 可视化结果
print("AS.CK :> 识别结果：",result)
# f1=plt.figure()
plt.title("AS.CK: The Prediction Number is " + str(result[0]))
fig = plt.gcf()
fig.canvas.set_window_title('AS.CK Figure 1')
plt.imshow(target_source)
plt.show()
